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 (MAC 3c: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 という組まで絞り込めた回答は少数であった。