Topics で読み物として読む
この HLD は実装詳細を含みます。機能の概念・設定・運用を読み物として読みたい場合は Topics 04 章: VRF / ECMP / 経路選択 を参照。
裏取りステータス: Code-verified
sonic-swss/orchagent/muxorch.cpp L1585 MuxOrch::updateRoute(const IpPrefix &pfx)、L2058 MuxOrch::containsNextHop()、L1824/1926/2019/2045/2050 の mux_nexthop_tb_ 出入り、L700 MuxCable::updateRoutes() / L724 MuxCable::updateRoutesForNextHop() から mux_orch_->updateRoute(rt->prefix) が駆動される経路を確認 (verified at: 2026-05-09)。
dual-tor mux 跨ぎの multi-nexthop route ループ回避(MuxOrch::updateRoute)¶
なぜ必要か¶
Gemini active-standby サーバ環境では 1 経路に複数の next-hop neighbor が指定され、それぞれが 異なる Ethernet ポート (= 異なる mux) に居る場合、片方の port が UT0 で active、もう片方が LT0 で active という非対称が起きる。すなわち 同一 ToR 内で 1 つは active neighbor、もう 1 つは standby neighbor という構成になる1。
このとき ECMP の半分が standby 側 nexthop に当たり、peer ToR の tunnel に流れ、peer ToR でも ECMP で半分が元 ToR に戻り、無限ループ(実質パケロス)が起きる1。
Neighbor 192.168.0.100 on Ethernet0 (Active on this ToR, Standby on peer)
Neighbor 192.168.0.101 on Ethernet4 (Standby on this ToR, Active on peer)
Route 11.11.11.0/24 nexthops 192.168.0.100, 192.168.0.101
↑ ↑
ここで standby を含む ECMP がループ原因
どう動くか¶
updateRoute() のロジック¶
MuxOrch に updateRoute(Route R1) を追加し、route の next-hop が複数ある場合 active が 1 つでもあればその 1 つに絞る1:
UpdateRoute(Route R1) {
if (R1 has more than 1 nexthops) {
if (ECMP group exists with nexthops) { remove stale ECMP group; }
for (NH in nexthops) {
if (NH is active) {
set route nexthop to NH;
return;
}
}
// active 不在
set route nexthop to tunnel;
}
}
優先順位1:
| 状態 | 動作 |
|---|---|
| nexthop 1 つ | no-op |
| nexthop 複数 + active 1 個以上 | 最初に見つかった active を sole nexthop |
| nexthop 複数 + 全 standby | tunnel を sole nexthop(peer ToR へ encap) |
flowchart TD
R[update notification: Route R1] --> N{nexthop 数}
N -->|1| NOP[no-op]
N -->|複数| EC[既存 ECMP group があれば削除]
EC --> L[loop nexthops]
L --> A{active?}
A -->|yes| S1[set sole nexthop = NH]
S1 --> X[return]
A -->|no| L
L --> AE{全 standby?}
AE -->|yes| TN[set sole nexthop = tunnel]
RouteOrch 側の補強¶
updateRoute() が機能するには m_nextHops (Route → NextHop 群キャッシュ) に mux neighbor が 個別展開 されている必要がある。既存実装では group 内 next-hop は個別エントリにならず、state 遷移時にループできない1。
routeorch.cpp に nextHops.is_mux_nexthop() 判定を追加し、mux neighbor から成る group を解凍する1:
if (ctx.nhg_index.empty() && nextHops.getSize() == 1 &&
!nextHops.is_overlay_nexthop() && !nextHops.is_srv6_nexthop() ||
nextHops.is_mux_nexthop())
{
for (auto it : nextHops.getNextHops()) {
if (!it.ip_address.isZero())
addNextHopRoute(it, r_key);
}
}
is_mux_nexthop() は NextHopGroupKey のメソッドで、group 内のいずれかが mux neighbor なら true。「group の neighbor は ALL mux か NONE mux」 という前提で、混在は想定しない1。
MuxOrch::containsNextHop()¶
mux neighbor 判定のため MuxOrch に追加1:
bool MuxOrch::containsNextHop(NextHopKey nh) {
return mux_nexthop_tb_.find(nh) != mux_nexthop_tb_.end();
}
駆動経路¶
sequenceDiagram
participant App
participant CDB as CONFIG_DB
participant RO as RouteOrch
participant MO as MuxOrch
participant ASIC
App->>CDB: route 11.11.11.0/24 NH=[A,B] (mux)
CDB->>RO: notify
RO->>RO: is_mux_nexthop() → true → 個別展開
RO->>MO: updateRoute(R1)
MO->>MO: A active? B active?
MO->>ASIC: route -> active NH (or tunnel)
MuxOrch は linkmgrd 由来の state 変化通知でも 影響を受ける全 route について updateRoute() を再評価 する1。
設定¶
CONFIG_DB / CLI / YANG 変更なし。dual-tor の既存設定 (MUX_CABLE / cable_type=active-standby 等) のまま、orchagent 内部挙動だけ変わる。
制限事項¶
- ECMP は実質的に無効化。active が複数あっても 最初の 1 つだけ を選び、帯域は ECMP の 1/N に縮退1
- 同一 group 内に mux と非 mux の混在は不可1
- 全 nexthop standby 時は tunnel route にフォールバック、peer ToR active 前提
- active fallback は 「最初に見つかった active」 で固定、負荷分散の意味なし
m_nextHopsキャッシュ整合性が崩れると古い NH に traffic が流れる risk
干渉する機能¶
MuxOrch:updateRoute()を新設、neighbor / tunnel と密結合RouteOrch:is_mux_nexthop()判定で個別展開linkmgrd状態通知: state 遷移ごとにupdateRoute()を駆動TunnelOrch: 全 standby 時の tunnel nexthop 供給- 既存 ECMP 経路: dual-tor mux 環境では実質無効化
トラブルシューティング¶
- 経路ループ → ASIC_DB で nexthop が単一に絞られているか、
MuxOrchログでupdateRoute()呼び出し確認 - nexthop が 常に tunnel →
show muxcable statusで active/standby 確認 - nexthop group のまま →
is_mux_nexthop()が false。mux_nexthop_tb_登録確認 - ECMP したい → 本 HLD は mux nexthop ECMP を許容しない 設計
コマンド例¶
複数 nexthop 経路 (ECMP) の登録と分散を確認する。
show ip route summary
redis-cli -n 0 keys 'ROUTE_TABLE*' | head
redis-cli -n 1 hgetall 'ASIC_STATE:SAI_OBJECT_TYPE_NEXT_HOP_GROUP*' 2>/dev/null | head
関連トピック¶
- Topics: Dual-ToR — active-standby と mux の全体像
- Topics: VRF / ECMP — ECMP と next-hop group の文脈
- prefix-based-mux-neighbors
- overlay-ecmp-enhancements