はじめに
この記事はシスコの有志による Cisco Systems Japan Advent Calendar 2025 (2枚目) の 22日目として投稿しています。
2017年版: https://qiita.com/advent-calendar/2017/cisco
2018年版: https://qiita.com/advent-calendar/2018/cisco
2019年版: https://qiita.com/advent-calendar/2019/cisco
2020年版: https://qiita.com/advent-calendar/2020/cisco
2020年版(2枚目): https://qiita.com/advent-calendar/2020/cisco2
2021年版: https://qiita.com/advent-calendar/2021/cisco
2021年版(2枚目): https://qiita.com/advent-calendar/2021/cisco2
2022年版(1,2): https://qiita.com/advent-calendar/2022/cisco
2023年版: https://qiita.com/advent-calendar/2023/cisco
2024年版: https://qiita.com/advent-calendar/2024/cisco
2025年版: https://qiita.com/advent-calendar/2025/cisco <--ここ
はじめに:金がない、機材もない、でもAIはやりたい
2025年、世はまさに 大AI時代 。
猫も杓子も「GPU」だの「推論」だのと言っています。ネットワークエンジニアへの無茶振りも加速する一方です。
こんな会話が世間一般で繰り広げられていることでしょう。
上司 「これからはAIバックエンドだよ。マイクロソフトがやってるような800GとかSRv6 uSIDとか、バリバリ検証してよ」
私 「御意(心の声:機材どこにあるんですか? 800Gスイッチって高級車買えますよね?)」
検証機材がない。でも勉強しないと時代に置いていかれる。
追い詰められて、「物理がないなら、論理で作ればいいじゃない」 というマリー・アントワネット的な思考に至ることもたくさんあるでしょう。
今回は、コンテナ型ルータ 「XRd」 と 「Containerlab」 を使い、自宅のPC内にAIデータセンターの縮図を「無課金」で召喚 します。
(逸般の誤家庭には空いてるLinuxの一台くらいありますよね?)
今回のミッション:自宅に「AI Fabric」を建てる
Microsoftが採用している、SRv6 uSIDを用いた AIバックエンドネットワーク を再現します。
https://www.segment-routing.net/images/MPLS-SRv6-WC-2025/Paris25-D2-1115_Hui-Rita.pdf
https://datatracker.ietf.org/doc/draft-filsfils-srv6ops-srv6-ai-backend/
本来なら数千万円コースの構成ですが、今回はDockerイメージと電気代だけで実現します。
▲ 今回構築するAIデータセンター(論理)の全貌
- Spine/Leaf: Cisco XRd (中身はガチのIOS-XR。プライド高めなのでメモリを爆食いします。サーバ側は32GBくらいほしくなります。)
- プロトコル: SRv6 uSID (ヘッダを圧縮する最新技術。AIは「帯域」が命なので、ヘッダのダイエットは必須)
手順①:Containerlabでデータセンターを召喚する
CMLとかXRd-tools使おうかと思ったのですが、containerだけならcontainerlabのほうが楽ですね。
これの何が凄いって、YAMLファイル(呪文)を一行書くだけで、勝手にLANケーブル(veth)を配線してくれるんです。(bridge経由じゃなくて)
夜な夜なLinux Bridgeを作成しては ip link set up を叩いていたあの日々はもう帰ってきません。
召喚の呪文 (topology.yaml)
name: ore-no-ai-dc
topology:
kinds:
cisco_xrd:
# ※お手持ちのXRdイメージを指定してください
image: ios-xr/xrd-control-plane:25.4.1
linux:
image: nicolaka/netshoot
nodes:
# 4台のXRdを召喚。メモリ? 気にしたら負けです。
spine1: { kind: cisco_xrd, startup-config: ./configs/spine1.cfg }
spine2: { kind: cisco_xrd, startup-config: ./configs/spine2.cfg }
leaf1: { kind: cisco_xrd, startup-config: ./configs/leaf1.cfg }
leaf2: { kind: cisco_xrd, startup-config: ./configs/leaf2.cfg }
# GPUのRDMA NIC役のLinux
host1: { kind: linux }
host2: { kind: linux }
links:
# ここに書くだけで配線完了。神か。
- endpoints: ["leaf1:Gi0-0-0-0", "spine1:Gi0-0-0-0"]
- endpoints: ["leaf1:Gi0-0-0-1", "spine2:Gi0-0-0-0"]
- endpoints: ["leaf2:Gi0-0-0-0", "spine1:Gi0-0-0-1"]
- endpoints: ["leaf2:Gi0-0-0-1", "spine2:Gi0-0-0-1"]
- endpoints: ["host1:eth1", "leaf1:Gi0-0-0-2"]
- endpoints: ["host2:eth1", "leaf2:Gi0-0-0-2"]
召喚実行
sudo containerlab deploy -t topology.yaml
エンターキーをッターン!と叩いて数分。
自宅にIOS-XRが4台立ち上がりました。 これでもう、気分はデータセンター管理者です。
tkamata@xrd-demo:~$ sudo containerlab deploy -t topology.yaml
13:28:20 INFO Containerlab started version=0.72.0
13:28:20 INFO Parsing & checking topology file=topology.yaml
13:28:20 INFO Creating docker network name=clab IPv4 subnet=172.20.20.0/24 IPv6 subnet=3fff:172:20:20::/64 MTU=0
13:28:20 INFO Creating lab directory path=/home/tkamata/clab-ore-no-ai-dc
13:28:20 INFO Creating container name=host1
13:28:20 INFO Creating container name=host2
13:28:20 INFO Creating container name=spine1
13:28:20 INFO Creating container name=leaf2
13:28:20 INFO Creating container name=spine2
13:28:20 INFO Creating container name=leaf1
13:28:22 INFO Running postdeploy actions for Cisco XRd 'spine2' node
13:28:22 INFO Created link: leaf1:Gi0-0-0-1 ▪┄┄▪ spine2:Gi0-0-0-0
13:28:23 INFO Created link: leaf2:Gi0-0-0-1 ▪┄┄▪ spine2:Gi0-0-0-1
13:28:23 INFO Created link: leaf1:Gi0-0-0-0 ▪┄┄▪ spine1:Gi0-0-0-0
13:28:23 INFO Created link: host1:eth1 ▪┄┄▪ leaf1:Gi0-0-0-2
13:28:23 INFO Running postdeploy actions for Cisco XRd 'leaf1' node
13:28:23 INFO Created link: host2:eth1 ▪┄┄▪ leaf2:Gi0-0-0-2
13:28:23 INFO Running postdeploy actions for Cisco XRd 'leaf2' node
13:28:23 INFO Created link: leaf2:Gi0-0-0-0 ▪┄┄▪ spine1:Gi0-0-0-1
13:28:23 INFO Running postdeploy actions for Cisco XRd 'spine1' node
13:28:23 INFO Adding host entries path=/etc/hosts
13:28:23 INFO Adding SSH config for nodes path=/etc/ssh/ssh_config.d/clab-ore-no-ai-dc.conf
13:28:26 INFO Failed fetching latest version information
╭──────────────────────────┬─────────────────────────────────┬─────────┬───────────────────╮
│ Name │ Kind/Image │ State │ IPv4/6 Address │
├──────────────────────────┼─────────────────────────────────┼─────────┼───────────────────┤
│ clab-ore-no-ai-dc-host1 │ linux │ running │ 172.20.20.5 │
│ │ nicolaka/netshoot:latest │ │ 3fff:172:20:20::5 │
├──────────────────────────┼─────────────────────────────────┼─────────┼───────────────────┤
│ clab-ore-no-ai-dc-host2 │ linux │ running │ 172.20.20.2 │
│ │ nicolaka/netshoot:latest │ │ 3fff:172:20:20::2 │
├──────────────────────────┼─────────────────────────────────┼─────────┼───────────────────┤
│ clab-ore-no-ai-dc-leaf1 │ cisco_xrd │ running │ 172.20.20.3 │
│ │ ios-xr/xrd-control-plane:25.4.1 │ │ 3fff:172:20:20::3 │
├──────────────────────────┼─────────────────────────────────┼─────────┼───────────────────┤
│ clab-ore-no-ai-dc-leaf2 │ cisco_xrd │ running │ 172.20.20.6 │
│ │ ios-xr/xrd-control-plane:25.4.1 │ │ 3fff:172:20:20::6 │
├──────────────────────────┼─────────────────────────────────┼─────────┼───────────────────┤
│ clab-ore-no-ai-dc-spine1 │ cisco_xrd │ running │ 172.20.20.7 │
│ │ ios-xr/xrd-control-plane:25.4.1 │ │ 3fff:172:20:20::7 │
├──────────────────────────┼─────────────────────────────────┼─────────┼───────────────────┤
│ clab-ore-no-ai-dc-spine2 │ cisco_xrd │ running │ 172.20.20.4 │
│ │ ios-xr/xrd-control-plane:25.4.1 │ │ 3fff:172:20:20::4 │
╰──────────────────────────┴─────────────────────────────────┴─────────┴───────────────────╯
tkamata@xrd-demo:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5acea3a0665d nicolaka/netshoot:latest "zsh" 5 minutes ago Up 5 minutes clab-ore-no-ai-dc-host2
1352ab2f392e ios-xr/xrd-control-plane:25.4.1 "/usr/local/sbin/init" 5 minutes ago Up 5 minutes clab-ore-no-ai-dc-leaf1
56b6b2caccc7 ios-xr/xrd-control-plane:25.4.1 "/usr/local/sbin/init" 5 minutes ago Up 5 minutes clab-ore-no-ai-dc-spine2
ffae6b07fc92 ios-xr/xrd-control-plane:25.4.1 "/usr/local/sbin/init" 5 minutes ago Up 5 minutes clab-ore-no-ai-dc-spine1
c609599e080b ios-xr/xrd-control-plane:25.4.1 "/usr/local/sbin/init" 5 minutes ago Up 5 minutes clab-ore-no-ai-dc-leaf2
2195e73d01d8 nicolaka/netshoot:latest "zsh" 5 minutes ago Up 5 minutes clab-ore-no-ai-dc-host1
手順2:SRv6 uSID で「パケットのダイエット」
AIのトラフィックは「象(Elephant Flow)」に例えられます。巨大すぎて、少しでも無駄があるとネットワークが詰まるのです。
従来のSRv6 (128bit) は「ヘッダが長すぎる」と嫌われがちでした。
そこで登場したのが uSID。
「128bitもいらんやろ、16bitでええやん」という、関西人並みのショートカット精神でヘッダを圧縮します。
設定は驚くほど簡単です。
! Leaf1の設定
segment-routing
srv6
locators
locator MAIN
prefix fcbb:bbbb:1::/48
! ↓この一行を入れるだけで、ルータが「uSIDモード」に覚醒します
micro-segment behavior unode psp-usd
!
!
!
!
たった一行 micro-segment behavior unode psp-usd。
これだけで、私のルータは最新のAIファブリック仕様に進化しました。
RP/0/RP0/CPU0:leaf1#show segment-routing srv6 sid
Sat Dec 20 13:41:49.332 UTC
*** Locator: 'MAIN' ***
SID Behavior Identification Owner State RW
-------------------------- ---------------- -------------------------------- ------------------ ----- --
fcbb:bbbb:1:: uN (PSP/USD) 'default':1 sidmgr InUse Y
fcbb:bbbb:1:e000:: uDT6 'default' bgp-65000 InUse Y
fcbb:bbbb:1:e001:: uA (PSP/USD) [Gi0/0/0/0, Link-Local]:0 isis-1 InUse Y
fcbb:bbbb:1:e002:: uA (PSP/USD) [Gi0/0/0/1, Link-Local]:0 isis-1 InUse Y
手順3:SRv6 Policyでパケットの通り道を決めてあげる
NIC側の設定が終わってないので、IPと経路を先に設定します。(面倒なのでIPv6だけ)
なぜか経路が先に入ってたので、replaceしておきました。
tkamata@xrd-demo:~$ docker exec -it clab-ore-no-ai-dc-host1 ip -6 addr add 2001:db8:10::2/64 dev eth1
tkamata@xrd-demo:~$ docker exec -it clab-ore-no-ai-dc-host1 ip -6 route replace default via 2001:db8:10::1 dev eth1 metric 1
tkamata@xrd-demo:~$ docker exec -it clab-ore-no-ai-dc-host1 ping6 -c 5 2001:db8:20::2
PING 2001:db8:20::2 (2001:db8:20::2) 56 data bytes
64 bytes from 2001:db8:20::2: icmp_seq=1 ttl=62 time=12.8 ms
64 bytes from 2001:db8:20::2: icmp_seq=2 ttl=62 time=7.08 ms
64 bytes from 2001:db8:20::2: icmp_seq=3 ttl=62 time=7.07 ms
64 bytes from 2001:db8:20::2: icmp_seq=4 ttl=62 time=7.09 ms
64 bytes from 2001:db8:20::2: icmp_seq=5 ttl=62 time=6.50 ms
--- 2001:db8:20::2 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4006ms
rtt min/avg/max/mdev = 6.500/8.116/12.843/2.373 ms
環境は整いました。ここからは 「Network Programmability」 の時間です。
通常のLoad balancing(ECMP)ではハッシュ計算で勝手に経路が決まってしまいます。
RDMAの通信はLow entropyと言われていて、RoCEv2環境では確実に他のトラフィックとCongestionしてしまうため、もはや「運任せ」にもならない状態です。
SRv6を用いたAI Backend networkではPolicyを使って**「このパケットはSpine1を通れ!」「そっちはSpine2だ!」** と指図して上げる必要があります。
本当はBGPを使ってPolicyを設定するんですが、今回はPythonとScapyを使って、自作したSRv6ヘッダ付きパケットをネットワークにねじ込みます。
Policy作成スクリプト (policy1.py)
from scapy.all import *
from scapy.layers.inet6 import IPv6, UDP, IPv6ExtHdrSegmentRouting
class IB_BTH(Packet):
name = "InfiniBand BTH"
fields_desc = [
XByteField("opcode", 0x0a), # 0x0a = RDMA Write Only
XByteField("se_m_pad_tver", 0),
XShortField("p_key", 0xFFFF),
XByteField("reserved", 0),
X3BytesField("dest_qp", 0x123456), # 宛先Queue Pair
XByteField("ack_req", 0),
X3BytesField("psn", 0),
]
gw_mac = "aa:c1:ab:b5:9b:61"
src_ip = "2001:db8:10::2"
final_dest = "2001:db8:20::2"
via_sid = "fcbb:bbbb:1001::"
sid_list = [final_dest, via_sid]
pkt = Ether(dst=gw_mac) / \
IPv6(src=src_ip, dst=via_sid) / \
IPv6ExtHdrSegmentRouting(
addresses=sid_list,
segleft=1,
type=4,
nh=17
) / \
UDP(sport=50000, dport=4791) / \
IB_BTH() / \
Raw(load="IMPORTANT_AI_GRADIENT_DATA_DO_NOT_DROP")
sendp(pkt, iface="eth1", verbose=0)
チャッピーと相談してRoCEv2 over SRv6のパケットを生成しました。
これを実行し、Spine1でキャプチャ取ったものをWiresharkで覗いてみると……
▲ 指定したSpine1を通過するAIパケット(のフリをしたパケット)
ちゃんと指定したSpine1経由でパケットが届いています。
まとめ:0円で未来は作れる
というわけで、高価な物理検証機がなくても、XRd × Containerlab × Python があれば、最新のAIネットワーク技術は検証できることが証明されました。(証明されていない。)
今回の成果:
- 自宅にAIデータセンター(論理)が建った。
- uSIDの挙動をパケットレベルで理解した。
- 財布へのダメージはゼロ(電気代を除く)。
この年末年始、みなさんもコタツに入りながら 「自宅AIデータセンター構築」 に挑戦してみてはいかがでしょうか?
私はこれから、コンテナを消すコマンド(containerlab destroy)を実行して、このデータセンターを虚無に帰そうと思います。
おしまい
免責事項
本サイトおよび対応するコメントにおいて表明される意見は、投稿者本人の個人的意見であり、シスコの意見ではありません。本サイトの内容は、情報の提供のみを目的として掲載されており、シスコや他の関係者による推奨や表明を目的としたものではありません。各利用者は、本Webサイトへの掲載により、投稿、リンクその他の方法でアップロードした全ての情報の内容に対して全責任を負い、本Web サイトの利用に関するあらゆる責任からシスコを免責することに同意したものとします。

