ICTSC2026 一次予選 問題解説: 問19
問19
概要
NVIDIA DGX Spark (GB10) を2台、ConnectX-7 の QSFP ポートで接続して NCCL を動かしたい。DGX Spark の NIC は次の構成である。
- ホスト(GB10)との接続: PCIe Gen5 x4 が 2 本
- 物理ポート: 200GbE の QSFP を 2 ポート
- OS から見える netdev: 4 つ(rail1〜rail4)。2 本の PCIe 経路と 2 つの物理ポートの組み合わせに対応する
- 物理ポート0 は VLAN 10、物理ポート1 は VLAN 20 に接続
- Pod へのアドレス払い出しは 4 本すべて同一の /24 から
症状: NCCL_IB_HCA で 1 レールに固定すると安定するが、4 レールをすべて使うと RETRY_EXC_ERR が断続的に発生する。
提示情報
資料1: gpu-node-01 の各 netdev のアドレス
gpu-node-01# ip -br addr show | grep '^rail'
rail1 UP 192.168.10.11/24
rail2 UP 192.168.10.12/24
rail3 UP 192.168.10.13/24
rail4 UP 192.168.10.14/24
資料2: 対向 gpu-node-02 の各 netdev
gpu-node-02# ip -br link show | grep '^rail'
rail1 UP 3c:ec:ef:41:8a:10
rail2 UP 3c:ec:ef:41:8a:11
rail3 UP 3c:ec:ef:41:8a:12
rail4 UP 3c:ec:ef:41:8a:13
gpu-node-02# ip -br addr show | grep '^rail'
rail1 UP 192.168.10.21/24
rail2 UP 192.168.10.22/24
rail3 UP 192.168.10.23/24
rail4 UP 192.168.10.24/24
資料3: ベンチマーク実行中の gpu-node-01 の近隣キャッシュ
gpu-node-01# ip neigh show | grep 192.168.10 | sort -t. -k4 -n
192.168.10.21 dev rail1 lladdr 3c:ec:ef:41:8a:10 REACHABLE
192.168.10.22 dev rail2 lladdr 3c:ec:ef:41:8a:10 REACHABLE
192.168.10.23 dev rail3 lladdr 3c:ec:ef:41:8a:12 REACHABLE
192.168.10.24 dev rail4 lladdr 3c:ec:ef:41:8a:12 REACHABLE
資料4: sysctl (両ノードで同一の値)
gpu-node-01# sysctl -a 2>/dev/null | grep -E 'conf\.all\.(arp_ignore|arp_announce|arp_filter|rp_filter)'
net.ipv4.conf.all.arp_announce = 0
net.ipv4.conf.all.arp_filter = 0
net.ipv4.conf.all.arp_ignore = 0
net.ipv4.conf.all.rp_filter = 1
gpu-node-02# sysctl -a 2>/dev/null | grep -E 'conf\.all\.(arp_ignore|arp_announce|arp_filter|rp_filter)'
net.ipv4.conf.all.arp_announce = 0
net.ipv4.conf.all.arp_filter = 0
net.ipv4.conf.all.arp_ignore = 0
net.ipv4.conf.all.rp_filter = 1
rail1〜rail4 の個別値はいずれも all と同じである。
設問
以下の4点について答えよ。
小問 (1)
資料から症状の原因を特定し、説明せよ。根拠を示すこと。
正解 (想定解答)
4 本の netdev (rail1〜rail4) がすべて同じ
192.168.10.0/24に属しており、資料4 のとおりarp_ignoreは既定値の 0 になっている。
この設定では、自分が持っているアドレス宛の ARP であれば、どのインターフェースからでも応答してしまう (ARP flux)。このことは資料2 と資料3 を突き合わせると確認できる。
資料2 では192.168.10.22はrail2(MAC3c:ec:ef:41:8a:11) のアドレスだが、資料3 では3c:ec:ef:41:8a:10(rail1の MAC) に解決されている。
同じく192.168.10.24も、本来はrail4(...:13) のはずが3c:ec:ef:41:8a:12(rail3の MAC) に解決されている。そのため、RoCEv2 が GID (netdev の IP) をもとに張った経路と、実際にフレームが流れる L2 の経路がずれてしまう。
正しく解決されているレールに固定している間は通信できるが、4 レールを同時に使うと宛先に届かない組み合わせが出てきて、RETRY_EXC_ERRが断続的に発生する。
得点の条件
部分点は設けず、以下の条件をすべて満たした回答を正解とした。
- 同一サブネットに複数のインターフェースがあることによる ARP flux (
arp_ignore=0で他のインターフェースのアドレスにも応答する動作) が原因だと書いている。用語が無くても動作の説明が正しければよい - 資料2 と資料3 の MAC の突き合わせを根拠として示している (
.22がrail1の MAC に、.24がrail3の MAC に解決されている。どちらか一方でよい)
小問 (2)
現場での一時的な回避策を示せ。また、全 netdev に arp_ignore=1 と arp_announce=2 を設定した場合、症状は完全に解消するか。理由とともに述べ、解消しないのであれば根本的な対処を示せ。あわせて、この sysctl を Kubernetes の Pod インターフェースへ適用する際の実装上の制約にも触れよ。
正解 (想定解答)
(i) 一時的な回避策
NCCL_IB_HCAで使う HCA を 1 本に固定する (例:NCCL_IB_HCA=mlx5_0)。
帯域は落ちるが、資料3 で正しい MAC に解決されているレール (rail1 や rail3) を選べば、通信相手が 1 つに決まるので安定する。(ii) sysctl だけで解消するか
arp_ignore=1とarp_announce=2を設定しても、完全には解消しない。
この構成では、同じ/24が VLAN 10 と VLAN 20 の 2 つのブロードキャストドメインに分かれている。
ARP の応答を正しくすると、今度は別の VLAN にあるレールのアドレスには ARP の応答が返らず、解決できなくなる。
カーネルは/24のプレフィックスを見て同じリンク上にいると判断して ARP を送るが、そのブロードキャストドメインには宛先がいないためである。
症状が「間違った MAC に解決される」から「解決できない」に変わるだけで、4 レールを総当たりで組む構成は成り立たない。(iii) 根本的な対処
レールごと (少なくとも VLAN ごと) に別のサブネットを割り当て、アドレスを払い出す側で分ける。
レールはそれぞれ別のファブリックで同じ L2 ではないので、同じサブネットを割り当てていること自体が間違いである。(iv) Kubernetes での実装上の制約
MacvlanNetworkなどの高レベルな CR では CNI チェーンを書けないので、sysctl を差し込めない。
NetworkAttachmentDefinitionを使い、macvlan → tuning の 2 段のチェーンにする必要がある。
また、Pod の作成時にインターフェースが作られる環境では、/etc/sysctl.d/に書いても反映されず、インターフェースが作られた後に設定を入れる仕組みが要る。
得点の条件
部分点は設けず、以下の条件をすべて満たした回答を正解とした。
- (i) 一時回避として
NCCL_IB_HCAで 1 レールに固定すると書いている (使う netdev を 1 本に絞るなど等価な方法でもよい) - (ii) 「完全には解消しない」と結論し、その理由として同一の
/24が VLAN 10 と VLAN 20 の 2 つの L2 ドメインにまたがっており、VLAN をまたぐ組では ARP を解決できないことを説明している - (iii) 根本対処として、レールまたは VLAN ごとに別のサブネットに分けると書いている
- (iv) Kubernetes での制約として、CNI チェーン (
NetworkAttachmentDefinitionで macvlan → tuning) が必要なこと、または/etc/sysctl.d/は Pod 作成時に作られるインターフェースに適用されないことのいずれかに触れている (等価な制約でもよい)
小問 (3)
症状を解消した後、ケーブル2本・4 netdev すべてを使ったときの理論上の上限帯域はいくらか。根拠を明示して答えよ。
正解 (想定解答)
約 252 Gbps である。
上限を決めているのはポートではなく PCIe である。ポートの合計は 200 GbE × 2 = 400 Gbps だが、ホストとの接続は PCIe Gen5 x4 が 2 本しかない。
PCIe Gen5 は 1 レーンあたり 32 GT/s なので x4 で 128 GT/s、128b/130b のエンコード分を引くと実効で 126.0 Gbps になる。
これが 2 本なので 252.1 Gbps となり、min(400, 252) = 252から、4 netdev をすべて使っても約 252 Gbps が上限になる。
得点の条件
部分点は設けず、以下の条件をすべて満たした回答を正解とした。
- PCIe 側が律速し、ポート合計の 400 Gbps は出ないと結論し、その理由 (PCIe Gen5 x4 × 2 本) を書いている
- 上限の数値が 245〜256 Gbps の範囲にある
小問 (4)
1 本のケーブル (物理ポート0) のみを使う場合、単一の netdev では上限がいくらになるか。また、そのポートを飽和させるにはどのような条件を満たせば良いか述べよ。
正解 (想定解答)
単一の netdev の上限は、PCIe Gen5 x4 の 1 本分の約 126 Gbps であり、200 GbE のポートを使い切れない。
ポートを飽和させるには、同じ物理ポートにつながり、かつ別々の PCIe 経路を通る 2 つの netdev を一緒に使う必要がある (socket-direct)。
こうするとホスト側が 126 × 2 = 252 Gbps になり、上限が PCIe から回線側に移るので、200 Gbps まで使い切れる。
NCCL では、両方の netdev をNCCL_IB_HCAに並べて指定する。また資料3 を見ると、同じ MAC に解決される組 (
rail1とrail2、rail3とrail4) は、それぞれ同じブロードキャストドメイン、つまり同じ物理ポートの側にあると分かる。
よって、一緒に使う組はrail1とrail2、またはrail3とrail4のどちらかになる。
得点の条件
部分点は設けず、以下の条件をすべて満たした回答を正解とした。
- 単一の netdev では 200 GbE ポートを使い切れず、上限は PCIe Gen5 x4 の 1 本分 (約 126 Gbps、120〜130 Gbps を許容) だと書いている
- 同一物理ポートかつ異なる PCIe 経路の 2 つの netdev を併用する (socket-direct) という条件を書いている
- 資料3 から、併用すべき組を
rail1+rail2またはrail3+rail4に絞り込んでいる
解説
この問題は、前半の小問 (1) (2) が ARP の話で、後半の小問 (3) (4) が帯域の話になっている。
ARP flux について
同じサブネットに複数のインターフェースを持たせたとき、どのインターフェースからでも ARP に応答してしまうのはバグではなく、Linux の既定の動作である。
arp_ignore=1 にすると「そのインターフェースが持つアドレス宛の ARP にだけ応答する」ようになり、arp_announce=2 にすると「送信するインターフェースのアドレスを送信元として名乗る」ようになる。
sysctl だけでは直らない理由
この sysctl は症状を抑えるだけで、構成の問題は残る。
本問の構成では、同じ /24 が VLAN 10 と VLAN 20 の 2 つの L2 ドメインに分かれているが、ARP の応答を正しくしても、今度は別の VLAN 側のアドレスが解決できなくなるだけである。
カーネルは /24 のプレフィックスを見て、同じリンク上にいると判断して ARP を送るが、そのブロードキャストドメインには宛先がいない。
また、NCCL は既定 (NCCL_CROSS_NIC=2) では同じ番号のレールどうしを優先して組むが、別のレールと組むことも許しているので、同じ VLAN の中に収まるとは限らない。
さらに、同じ /24 への経路が 4 本あるため、ARP の解決が QP を張ったレール以外から行われることもある。
設計としては、レールごとに別のサブネットにするのが正しい。
レールはそれぞれ別のファブリックで同じ L2 ではないので、アドレスを払い出す側で分けるべきである。
Kubernetes 上で sysctl を入れる場合は、小問 (2) の (iv) で述べたとおり、CNI チェーンの書き方と、インターフェースが作られるタイミングに気をつける必要がある。
なお、rp_filter はカーネルのネットワークスタックを通る通信 (NCCL のブートストラップなど) には影響するが、RoCEv2 のデータは HCA が処理し、カーネルの IPv4 の受信処理を通らないので、本問の RETRY_EXC_ERR には関係しない。
帯域の上限について
ポートの数だけを数えて帯域を見積もると、400 対 252 で 1.6 倍ほど多く見積もってしまう。
GPU ノードの NIC の帯域は、ポートのリンク速度ではなく、ホストとの接続の太さで決まることがある。
小問 (4) は、実際に運用するうえで一番重要なところである。
1 本のケーブルに対して netdev が 2 つ見えるのは冗長化のためではなく、PCIe の帯域を束ねて 1 ポートを使い切るための仕組み (socket-direct) である。
これを片方だけ使うと、200G のポートの 6 割強しか出ず、NCCL では、両方を NCCL_IB_HCA に並べて指定する必要がある。
比較として、Hopper 世代の NVL4 ボード (ConnectX-7 が PCIe Gen5 x16 で、独立した 400GbE ポートにつながる) では、同じ ARP の対処だけで 4 レールの合計が 1509 Gbps (リンク合計 1600 Gbps の 94%) に達する。
Hopper 世代ではポート律速、DGX Spark では PCIe 律速である。
講評
各小問の正解チーム数は次のとおり。
| 小問 | 正解チーム数 / 回答チーム数 |
|---|---|
| (1) | 43 / 47 |
| (2) | 30 / 47 |
| (3) | 42 / 47 |
| (4) | 12 / 48 |
(1) と (3) はほとんどのチームが正答にたどり着いていた。
(2) は (ii) で「完全には解消しない」と結論しても、理由を rp_filter や経路選択の偏りだけで説明している回答が多くあった。
同一サブネットを VLAN の異なる複数の netdev に載せていること自体が原因である点まで書けたかどうかで差がついた。
(4) は 2 本の併用までは多くの回答が書けていたが、rail1+rail2 または rail3+rail4 という組まで絞り込めた回答は少数であった。