RouteOrch event / notification¶
概要¶
orchagent の RouteOrch は経路の SAI プログラミング完了時に 2 種類の通知 を送出する。
| 種別 | 機構 | 送信先 | 目的 |
|---|---|---|---|
| ResponsePublisher | publishRouteState() |
APPL_STATE_DB + APPL_DB_ROUTE_TABLE_RESPONSE_CHANNEL |
fpmsyncd へのプログラミング結果フィードバック |
| NextHopObserver | notifyNextHopChangeObservers() |
内部 Observer(NeighOrch, MirrorOrch 等) | ルーティング変化のオーケストレーション内通知 |
関連ページ
- APPL_DB の
ROUTE_TABLEフィールド:ROUTE_TABLE (APPL_DB) - STATE_DB / APPL_STATE_DB のテーブル構造:
ROUTE_TABLE (STATE_DB/APPL_STATE_DB) - fpmsyncd のハンドラ分岐:
ROUTE_TABLE handler 分岐
データフロー¶
flowchart LR
APPDB[("APPL_DB\nROUTE_TABLE")]
OA["RouteOrch\norchagent"]
SAI["SAI\nsai_route_api"]
APPLSTATE[("APPL_STATE_DB\nROUTE_TABLE")]
RESP["APPL_DB_ROUTE_TABLE\n_RESPONSE_CHANNEL"]
FPM["fpmsyncd\n(RESPONSE_CHANNEL 購読)"]
OBS["内部 Observer\n(NeighOrch 等)"]
APPDB -->|"subscribe"| OA
OA -->|"sai_route_api"| SAI
OA -->|"publishRouteState()\n[SET: protocol+err_str]"| APPLSTATE
OA -->|"publishRouteState()\n[通知]"| RESP
OA -->|"notifyNextHopChangeObservers()\nNextHopUpdate"| OBS
RESP --> FPM
1. ResponsePublisher 通知¶
呼び出し契機¶
RouteOrch::publishRouteState() は以下のタイミングで呼ばれる1:
| 状況 | 行番号 |
|---|---|
addRoute() 内: SAI エラー時 |
L923 |
addRoute() 内: 既存エントリと完全一致(再 publish) |
L1050 |
addRoute() 内: 重複エントリ追加スキップ時 |
L1090 |
addRoutePost() 末尾: SAI 操作完了後 |
L2729 |
removeRoutePost() 末尾: SAI 操作完了後 |
L2970 |
送出フィールド¶
// routeorch.cpp L3185–3202
void RouteOrch::publishRouteState(const RouteBulkContext& ctx, const ReturnCode& status)
{
std::vector<FieldValueTuple> fvs;
if (ctx.is_set)
{
fvs.emplace_back("protocol", ctx.protocol);
}
const bool replace = false;
m_publisher.publish(APP_ROUTE_TABLE_NAME, ctx.key, fvs, status, replace);
}
| フィールド | SET 操作時 | DEL 操作時 |
|---|---|---|
protocol |
ctx.protocol(空文字列またはプロトコル名) |
送信しない(fvs が空) |
err_str |
ResponsePublisher が自動付与 |
同上(自動付与) |
protocol フィールドのデフォルト¶
RouteBulkContext::protocol の初期値は "":
APPL_DB の SET メッセージから protocol フィールドを読み取る (L785–788)1:
APPL_DB の protocol フィールド |
APPL_STATE_DB の protocol 値 |
|---|---|
"bgp" 等(空でない文字列) |
そのままコピー |
| 存在しない、または空文字列 | "" (空文字列) |
err_str フィールドのデフォルト¶
ResponsePublisher::publish() が err_str を自動付与する (response_publisher.cpp L102–103)3:
swss::FieldValueTuple err_str("err_str", PrependedComponent(status) + status.message());
intent_attrs_copy.insert(intent_attrs_copy.begin(), err_str);
PrependedComponent() の決定ロジック (response_publisher.cpp L16–28)3:
std::string PrependedComponent(const ReturnCode &status)
{
if (status.ok()) return "";
if (status.isSai()) return "[SAI] ";
return "[OrchAgent] ";
}
| SAI 結果 | err_str の値 |
|---|---|
| 成功 | "SWSS_RC_SUCCESS" |
| SAI エラー | "[SAI] <エラーメッセージ>" |
| OrchAgent エラー | "[OrchAgent] <エラーメッセージ>" |
APPL_STATE_DB 書き込み条件¶
ResponsePublisher は以下の条件でのみ APPL_STATE_DB を更新する (response_publisher.cpp L133–138)3:
| 操作 | SAI 結果 | APPL_STATE_DB |
|---|---|---|
| SET | 成功 | protocol + err_str を書き込む |
| SET | 失敗 | 書き込まない(RESPONSE_CHANNEL 通知のみ) |
| DEL | 成功 | エントリを削除(DEL_COMMAND) |
| DEL | 失敗 | 書き込まない |
バッファリングと flush¶
RouteOrch コンストラクタ (routeorch.cpp L57–58)1:
setBuffered(true): 通知は Redis パイプライン経由でバッファリングm_directDbWrite = true: DB 書き込みはパイプライン経由(非スレッド)doTask()の最後に必ずflush()が呼ばれる (routeorch.cpp L1231)1:
/* Flush response publisher so route notifications reach fpmsyncd every batch.
* Without this, notifications stay buffered in the Redis pipeline until the
* next batch. */
m_publisher.flush();
2. NextHopObserver 内部通知¶
NextHopUpdate 構造体¶
notifyNextHopChangeObservers() が送出する NextHopUpdate 構造体 (routeorch.h L61–68)2:
struct NextHopUpdate
{
sai_object_id_t vrf_id;
IpAddress destination;
IpPrefix prefix;
NextHopGroupKey nexthopGroup;
};
| フィールド | 型 | 説明 |
|---|---|---|
vrf_id |
sai_object_id_t |
VRF の SAI オブジェクト ID |
destination |
IpAddress |
Observer が追跡しているホスト IP アドレス |
prefix |
IpPrefix |
現在の最長プレフィックスマッチ |
nexthopGroup |
NextHopGroupKey |
新しい nexthop グループキー |
nexthopGroup にデフォルト値はなく、常にその時点の実際の nexthop グループキーが設定される。
通知発火条件¶
// routeorch.cpp L1270
void RouteOrch::notifyNextHopChangeObservers(
sai_object_id_t vrf_id, const IpPrefix &prefix,
const NextHopGroupKey &nexthops, bool add)
ADD 時(add=true):
- 新規ルートが追加され、そのルートが当該 Observer 宛先の最長プレフィックスマッチになった場合
- 既存ルートの nexthopGroup が変化し、そのルートが最長プレフィックスマッチの場合
DEL 時(add=false):
- 削除されたルートが最長プレフィックスマッチであった場合(次の最長マッチを NextHopUpdate で再通知)
attach() 時の即時通知¶
Observer が attach() した時点で最長プレフィックスマッチが存在すれば即時通知 (routeorch.cpp L340–350)1:
// Trigger next hop change for the first time the observer is attached
auto route = observerEntry->second.routeTable.rbegin();
if (route != observerEntry->second.routeTable.rend())
{
NextHopUpdate update = { vrf_id, dstAddr, route->first, route->second.nhg_key };
observer->update(SUBJECT_TYPE_NEXTHOP_CHANGE, static_cast<void *>(&update));
}
デフォルトルートの存在保証¶
Observer 追跡テーブルには必ずデフォルトルート (0.0.0.0/0 / ::/0) が含まれるため、
最長プレフィックスマッチは常に 1 件以上存在する:
/* Table should not be empty. Default route should always exists. */
assert(!entry.second.routeTable.empty());
主な Observer¶
| Observer | 用途 |
|---|---|
NeighOrch |
ARP/ND エントリの nexthop 変化追跡 |
MirrorOrch |
ミラーセッションの宛先 IP 解決 |
TunnelDecapOrch |
トンネル decap 処理の nexthop 解決 |
コード由来デフォルト詳細 (Phase A)¶
ResponsePublisher — protocol フィールドのデフォルト: ""¶
RouteBulkContext::protocol は初期化時に空文字列:
APPL_DB に protocol フィールドが存在する場合のみ上書き (L785–788):
protocolフィールドが存在しない、または空文字列 →ctx.protocol = ""(空文字列)のまま APPL_STATE_DB にprotocol: ""として書き込まれるprotocolフィールドが空でない文字列 → その値をそのままコピー
ResponsePublisher — err_str フィールドのデフォルト: "SWSS_RC_SUCCESS"¶
SAI 成功時は PrependedComponent(status) が "" を返し、status.message() が "SWSS_RC_SUCCESS" になる:
// response_publisher.cpp L102
swss::FieldValueTuple err_str("err_str", PrependedComponent(status) + status.message());
- 成功時の
err_str値:"SWSS_RC_SUCCESS"(プレフィックスなし) - SAI エラー時:
"[SAI] "+ エラーメッセージ - OrchAgent エラー時:
"[OrchAgent] "+ エラーメッセージ
ResponsePublisher — flush タイミング¶
doTask() の末尾で必ず flush() が呼ばれるため、バッチ処理完了後に全通知がまとめて送出される。個別 route ごとに flush は 行われない。
NextHopObserver — NextHopUpdate のデフォルト値¶
NextHopUpdate 構造体のフィールドはすべて呼び出し時の実際の値で埋められる。構造体自体にデフォルト値は定義されていない:
nexthopGroupが空(nexthop なし)の状態で通知されるのは、削除時に次の最長マッチが blackhole ルートのみの場合。
制約¶
publishRouteState()は SET 操作時のみprotocolを送信する。DEL 操作時はfvsが空のため APPL_STATE_DB からエントリが削除される。- SAI プログラミング失敗時は APPL_STATE_DB への書き込みは行われないが、RESPONSE_CHANNEL への通知は行われる。
notifyNextHopChangeObservers()は 最長プレフィックスマッチが変化した場合のみ 通知を発火する。最長マッチが同じルートで nexthopGroup も同じ場合は通知しない。- Observer は
attach()で登録した IP アドレスを含む最長プレフィックスマッチの変化のみを受け取る。
購読者 (consumer)¶
ResponsePublisher 通知¶
| プロセス | 参照 | 用途 |
|---|---|---|
fpmsyncd |
APPL_DB_ROUTE_TABLE_RESPONSE_CHANNEL |
SAI プログラミング結果を FRR へフィードバック |
route_check.py |
APPL_STATE_DB ROUTE_TABLE |
APPL_DB と APPL_STATE_DB の整合確認 |
NextHopObserver 通知¶
| Observer | attach() 箇所 |
|---|---|
NeighOrch |
ネイバー解決時 |
MirrorOrch |
ミラーセッション設定時 |
関連リファレンス¶
- APPL_DB:
ROUTE_TABLE - STATE_DB / APPL_STATE_DB:
ROUTE_TABLE (STATE_DB/APPL_STATE_DB) - CONFIG_DB:
STATIC_ROUTE - handler 分岐:
ROUTE_TABLE handler 分岐
引用元¶
運用ヒント¶
確認コマンド¶
# APPL_STATE_DB の経路プログラミング結果確認
sonic-db-cli APPL_STATE_DB hgetall 'ROUTE_TABLE:10.0.0.0/24'
# err_str でエラー経路を検索
sonic-db-cli APPL_STATE_DB keys 'ROUTE_TABLE:*' | while read k; do
err=$(sonic-db-cli APPL_STATE_DB hget "$k" err_str)
[ "$err" != "SWSS_RC_SUCCESS" ] && echo "$k: $err"
done
# RESPONSE_CHANNEL の通知を監視(デバッグ用)
redis-cli -n 0 subscribe APPL_DB_ROUTE_TABLE_RESPONSE_CHANNEL
典型エントリ例¶
# APPL_STATE_DB: BGP 経路のプログラミング成功
APPL_STATE_DB ROUTE_TABLE:10.1.0.0/24
err_str: SWSS_RC_SUCCESS
protocol: bgp
# APPL_STATE_DB: protocol フィールドなし経路(static など fpmsyncd 経由以外)
APPL_STATE_DB ROUTE_TABLE:192.168.1.0/24
err_str: SWSS_RC_SUCCESS
protocol: (空文字列)
よくある問題¶
err_strが"[SAI] ..."→ SAI プログラミング失敗。/var/log/syslogの orchagent ログで詳細を確認する。- APPL_STATE_DB にエントリが存在しない → SAI 失敗または DEL 操作後。
RESPONSE_CHANNELのログを確認する。 protocolが空文字列 → APPL_DB のROUTE_TABLEエントリにprotocolフィールドが存在しない(静的経路や一部の直接書き込みツールで発生する)。
-
RouteOrch 実装:
orchagent/routeorch.cpp. https://github.com/sonic-net/sonic-swss/blob/4305596156d70e9797e8a881b3d19b46de0bce0d/orchagent/routeorch.cpp ↩↩↩↩↩ -
RouteOrch ヘッダ:
orchagent/routeorch.h. https://github.com/sonic-net/sonic-swss/blob/4305596156d70e9797e8a881b3d19b46de0bce0d/orchagent/routeorch.h ↩ -
ResponsePublisher 実装:
orchagent/response_publisher.cpp. https://github.com/sonic-net/sonic-swss/blob/4305596156d70e9797e8a881b3d19b46de0bce0d/orchagent/response_publisher.cpp ↩↩↩